<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>并发编程-FutureTask | JavaPool</title>
    <meta name="generator" content="VuePress 1.9.2">
    <link rel="icon" href="/img/favicon.ico">
    <meta name="description" content="java pool icu">
    <meta name="keywords" content="vuepress,theme,blog,vdoing">
    <meta name="theme-color" content="#a1cd00">
    
    <link rel="preload" href="/assets/css/0.styles.6964efbe.css" as="style"><link rel="preload" href="/assets/js/app.c5f14b06.js" as="script"><link rel="preload" href="/assets/js/2.0bb8723e.js" as="script"><link rel="preload" href="/assets/js/11.3f64ae04.js" as="script"><link rel="prefetch" href="/assets/js/10.56cf0803.js"><link rel="prefetch" href="/assets/js/12.02afd2cb.js"><link rel="prefetch" href="/assets/js/13.635b7092.js"><link rel="prefetch" href="/assets/js/14.f10556e8.js"><link rel="prefetch" href="/assets/js/15.27d8470a.js"><link rel="prefetch" href="/assets/js/16.70efe620.js"><link rel="prefetch" href="/assets/js/17.a79eaec6.js"><link rel="prefetch" href="/assets/js/18.aa4c8485.js"><link rel="prefetch" href="/assets/js/19.d98d039e.js"><link rel="prefetch" href="/assets/js/20.31b4dba4.js"><link rel="prefetch" href="/assets/js/21.c5f5372e.js"><link rel="prefetch" href="/assets/js/3.36e473cd.js"><link rel="prefetch" href="/assets/js/4.862e5a4f.js"><link rel="prefetch" href="/assets/js/5.81a4a7b6.js"><link rel="prefetch" href="/assets/js/6.634b1bae.js"><link rel="prefetch" href="/assets/js/7.00cec9d7.js"><link rel="prefetch" href="/assets/js/8.165e4749.js"><link rel="prefetch" href="/assets/js/9.5122111b.js">
    <link rel="stylesheet" href="/assets/css/0.styles.6964efbe.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/img/logo.png" alt="JavaPool" class="logo"> <span class="site-name can-hide">JavaPool</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <!----></div></header> <div class="sidebar-mask"></div> <div class="sidebar-hover-trigger"></div> <aside class="sidebar" style="display:none;"><!----> <!---->  <ul class="sidebar-links"><li><a href="/pages/f0d781/" class="sidebar-link">并发编程三大核心问题</a></li><li><a href="/pages/f94dea/" class="sidebar-link">深入理解线程池</a></li><li><a href="/pages/6c4806/" class="sidebar-link">线程池</a></li><li><a href="/pages/76d299/" aria-current="page" class="active sidebar-link">并发编程-FutureTask</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level2"><a href="/pages/76d299/#_1-runnable、callable、future、futuretask" class="sidebar-link">1. Runnable、Callable、Future、FutureTask</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/76d299/#_1-1-runnable" class="sidebar-link">1.1 Runnable</a></li><li class="sidebar-sub-header level3"><a href="/pages/76d299/#_1-2-callable" class="sidebar-link">1.2 Callable</a></li><li class="sidebar-sub-header level3"><a href="/pages/76d299/#_1-3-future" class="sidebar-link">1.3 Future</a></li><li class="sidebar-sub-header level3"><a href="/pages/76d299/#_1-4-futuretask" class="sidebar-link">1.4 FutureTask</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/76d299/#_2-futuretask类结构" class="sidebar-link">2. FutureTask类结构</a></li><li class="sidebar-sub-header level2"><a href="/pages/76d299/#_3-futuretask状态" class="sidebar-link">3. FutureTask状态</a></li><li class="sidebar-sub-header level2"><a href="/pages/76d299/#_4-执行任务run" class="sidebar-link">4. 执行任务run()</a></li><li class="sidebar-sub-header level2"><a href="/pages/76d299/#_5-获取任务返回值get-方法" class="sidebar-link">5. 获取任务返回值get()方法</a></li><li class="sidebar-sub-header level2"><a href="/pages/76d299/#_6-取消任务-cancel" class="sidebar-link">6. 取消任务 cancel()</a></li></ul></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="articleInfo-wrap" data-v-06225672><div class="articleInfo" data-v-06225672><ul class="breadcrumbs" data-v-06225672><li data-v-06225672><a href="/" title="首页" class="iconfont icon-home router-link-active" data-v-06225672></a></li> <li data-v-06225672><a href="/categories/?category=%E5%B9%B6%E5%8F%91%E5%A4%9A%E7%BA%BF%E7%A8%8B" title="分类" data-v-06225672>并发多线程</a></li></ul> <div class="info" data-v-06225672><div title="作者" class="author iconfont icon-touxiang" data-v-06225672><a href="https://mp.weixin.qq.com/s?__biz=MzAxMjEwMzQ5MA==&amp;mid=2448893268&amp;idx=2&amp;sn=a1aeb955fbbba6af7c0914abd3eb4399&amp;chksm=8fb57f79b8c2f66f3bf500776965d4fc305e273e408d7fc33c51da813ecfa8f237e98ce77186&amp;scene=178&amp;cur_album_id=1348578428257353729#rd" target="_blank" title="作者" class="beLink" data-v-06225672>java进阶架构师</a></div> <div title="创建时间" class="date iconfont icon-riqi" data-v-06225672><a href="javascript:;" data-v-06225672>2021-12-27</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-title">目录</div> <div class="right-menu-content"></div></div></div> <h1><img src="">并发编程-FutureTask<span class="title-tag">转载</span></h1> <!----> <div class="theme-vdoing-content content__default"><h1 id="并发编程-futuretask"><a href="#并发编程-futuretask" class="header-anchor">#</a> 并发编程-FutureTask</h1> <p>线程池源码中出现了很多Callable、Future、FutureTask等以前没介绍过的接口，尤其是线程池提交任务时总是把任务封装成FutureTask，今天就来为大家解惑：</p> <ol><li>Runnable、Callable、Future、FutureTask</li> <li>FutureTask类结构</li> <li>FutureTask状态</li> <li>执行任务 run()方法</li> <li>获取任务返回值 get()方法</li> <li>取消任务 cancel()方法</li></ol> <h2 id="_1-runnable、callable、future、futuretask"><a href="#_1-runnable、callable、future、futuretask" class="header-anchor">#</a> 1. Runnable、Callable、Future、FutureTask</h2> <h3 id="_1-1-runnable"><a href="#_1-1-runnable" class="header-anchor">#</a> 1.1 Runnable</h3> <p>Runnable接口只有一个run方法，而run方法的返回值是void，所以线程执行完之后没有返回值。</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">Runnable</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="_1-2-callable"><a href="#_1-2-callable" class="header-anchor">#</a> 1.2 Callable</h3> <p>在很多场景下，我们通过线程来异步执行任务之后，希望获取到任务的执行结果。比如RPC框架中，需要异步获取任务返回值。这种情况下，Runnable无法获取返回值就无法满足需求了，因此Callable就出现了。</p> <p>Callable也是一个接口，也只有一个call()方法，不同的是Callable的call()方法有是有返回值的，返回值的类型是一个泛型，泛型由创建Callable对象时指定。</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">Callable</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">V</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
 <span class="token class-name">V</span> <span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="_1-3-future"><a href="#_1-3-future" class="header-anchor">#</a> 1.3 Future</h3> <p>要想获得Callable的返回值就需要用到Future接口。Futrue可以监视和控制Callable任务的执行情况，如对执行结果进行取消、查询是否完成、获取结果等。</p> <p>如：当一个任务通过线程池的submit()方法提交到线程池后，线程池会返回一个Future类型的对象，我们可以通过Future对象来获取任务在线程池中的状态。</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">Future</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">V</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
    <span class="token keyword">boolean</span> <span class="token function">cancel</span><span class="token punctuation">(</span><span class="token keyword">boolean</span> mayInterruptIfRunning<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">boolean</span> <span class="token function">isCancelled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">boolean</span> <span class="token function">isDone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">V</span> <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">ExecutionException</span><span class="token punctuation">;</span>
    <span class="token class-name">V</span> <span class="token function">get</span><span class="token punctuation">(</span><span class="token keyword">long</span> timeout<span class="token punctuation">,</span> <span class="token class-name">TimeUnit</span> unit<span class="token punctuation">)</span>
            <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">ExecutionException</span><span class="token punctuation">,</span> <span class="token class-name">TimeoutException</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><ul><li>cancel方法：用来取消任务，如果取消任务成功则返回true，如果取消任务失败则返回false。
mayInterruptIfRunning参数用来表示是否需要中断线程，如果传true，表示需要中断线程，那么就会将任务的状态设置为INTERRUPTING；如果为false，那么就会将任务的状态设置为CANCELLED（关于任务的状态INTERRUPTING和CANCELLED后面会说明）</li> <li>isCancelled方法：表示任务是否被取消成功，如果在任务正常完成前被取消成功，则返回 true</li> <li>isDone方法：表示任务是否已经完成，若任务完成，则返回true</li> <li>get()方法：用来获取执行结果，这个方法会产生阻塞，会一直等到任务执行完毕才返回。</li> <li>get(long timeout, TimeUnit unit)方法：获取执行结果，如果在指定时间内，还没获取到结果，就直接返回null。</li></ul> <p>举例：Future获取Callable任务的返回值</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FutureExample</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">ExecutionException</span> <span class="token punctuation">{</span>
        <span class="token class-name">ExecutorService</span> threadPool <span class="token operator">=</span> <span class="token class-name">Executors</span><span class="token punctuation">.</span><span class="token function">newCachedThreadPool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Future</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> future <span class="token operator">=</span> threadPool<span class="token punctuation">.</span><span class="token function">submit</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Callable</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token annotation punctuation">@Override</span>
            <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
                <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">2000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">return</span> <span class="token string">&quot;结果&quot;</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;Callable返回值=&quot;</span> <span class="token operator">+</span> future<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>输出结果：</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token class-name">Callable</span>返回值<span class="token operator">=</span>结果
</code></pre></div><h3 id="_1-4-futuretask"><a href="#_1-4-futuretask" class="header-anchor">#</a> 1.4 FutureTask</h3> <p>FutureTask是Runnable和Future的实现类，既可以作为Runnable被线程执行，又可以作为Future得到Callable的返回值。</p> <p><img src="" alt="图片"></p> <p>当线程池调用submit()方法来向线程池中提交任务时，无论提交的是Runnable类型的任务，还是提交的是Callable类型的任务，最终都是将任务封装成一个FutureTask对象，我们可以通过这个FutureTask对象来获取任务在线程池中的状态。</p> <div class="language-java extra-class"><pre class="language-java"><code>    <span class="token keyword">public</span> <span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">Future</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token function">submit</span><span class="token punctuation">(</span><span class="token class-name">Callable</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> task<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>task <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">NullPointerException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 调用newTaskFor()将Callable任务封装成一个FutureTask</span>
        <span class="token class-name">RunnableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> ftask <span class="token operator">=</span> <span class="token function">newTaskFor</span><span class="token punctuation">(</span>task<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 执行任务</span>
        <span class="token function">execute</span><span class="token punctuation">(</span>ftask<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> ftask<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// newTaskFor</span>
    <span class="token keyword">protected</span> <span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">RunnableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token function">newTaskFor</span><span class="token punctuation">(</span><span class="token class-name">Callable</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> callable<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 直接new一个FutureTask对象</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">FutureTask</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>callable<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
</code></pre></div><h2 id="_2-futuretask类结构"><a href="#_2-futuretask类结构" class="header-anchor">#</a> 2. FutureTask类结构</h2> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FutureTask</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">V</span><span class="token punctuation">&gt;</span></span> <span class="token keyword">implements</span> <span class="token class-name">RunnableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">V</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
    <span class="token comment">/** state变量用来保存任务的状态 */</span>
    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">int</span> state<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">NEW</span>          <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">COMPLETING</span>   <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">NORMAL</span>       <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">EXCEPTIONAL</span>  <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">CANCELLED</span>    <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">INTERRUPTING</span> <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">INTERRUPTED</span>  <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span>
    
    <span class="token comment">/** 提交的任务，Runnable类型的任务会通过Executors.callable()来转变为Callable */</span>
    <span class="token keyword">private</span> <span class="token class-name">Callable</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">V</span><span class="token punctuation">&gt;</span></span> callable<span class="token punctuation">;</span>
    <span class="token comment">/** 用来保存Callable的call()方法的返回值 */</span>
    <span class="token keyword">private</span> <span class="token class-name">Object</span> outcome<span class="token punctuation">;</span>
    <span class="token comment">/** 执行Callable任务的线程 **/</span>
    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token class-name">Thread</span> runner<span class="token punctuation">;</span>
    <span class="token comment">/**
     * 任务未完成时，调用get方法获取结果的线程会阻塞等待
     * waiters用于保存这些线程
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token class-name">WaitNode</span> waiters<span class="token punctuation">;</span>
    
    <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">WaitNode</span> <span class="token punctuation">{</span>
        <span class="token keyword">volatile</span> <span class="token class-name">Thread</span> thread<span class="token punctuation">;</span>
        <span class="token keyword">volatile</span> <span class="token class-name">WaitNode</span> next<span class="token punctuation">;</span>
        <span class="token class-name">WaitNode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> thread <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="_3-futuretask状态"><a href="#_3-futuretask状态" class="header-anchor">#</a> 3. FutureTask状态</h2> <p>FutureTask任务的状态如下：</p> <div class="language-java extra-class"><pre class="language-java"><code>    <span class="token comment">// 任务的初始状态，当新建一个FutureTask任务时，state值默认为NEW</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">NEW</span>          <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token comment">// 任务处于完成中，也就是正在执行还未设置返回值</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">COMPLETING</span>   <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token comment">// 任务正常被执行完成，并将任务的返回值赋值给outcome属性之后</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">NORMAL</span>       <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>
    <span class="token comment">// 任务出了异常，并将异常对象赋值给outcome属性之后</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">EXCEPTIONAL</span>  <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>
    <span class="token comment">// 调用cancle(false)，任务被取消了</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">CANCELLED</span>    <span class="token operator">=</span> <span class="token number">4</span><span class="token punctuation">;</span>
    <span class="token comment">// 调用cancle(true)，任务中断，但是在线程中断之前</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">INTERRUPTING</span> <span class="token operator">=</span> <span class="token number">5</span><span class="token punctuation">;</span>
    <span class="token comment">//  调用cancle(true)，任务中断，但是在线程中断之后</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> <span class="token constant">INTERRUPTED</span>  <span class="token operator">=</span> <span class="token number">6</span><span class="token punctuation">;</span>
</code></pre></div><p>状态变化如下图：</p> <p><img src="/assets/img/20210714002.d0054a95.png" alt="图片"></p> <h2 id="_4-执行任务run"><a href="#_4-执行任务run" class="header-anchor">#</a> 4. 执行任务run()</h2> <ol><li>执行future.callable.call()，执行任务；</li> <li>执行成功，设置结果outcome；</li> <li>逐个唤醒waiters中的线程去获取执行结果。</li></ol> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
 <span class="token comment">/*
  * 1. 不是NEW状态，不能执行
  * 2. 设置runner失败，不能执行
  */</span>
 <span class="token keyword">if</span> <span class="token punctuation">(</span>state <span class="token operator">!=</span> <span class="token constant">NEW</span> <span class="token operator">||</span>
  <span class="token operator">!</span><span class="token constant">UNSAFE</span><span class="token punctuation">.</span><span class="token function">compareAndSwapObject</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> runnerOffset<span class="token punctuation">,</span>
          <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span><span class="token punctuation">;</span>
 <span class="token keyword">try</span> <span class="token punctuation">{</span>
  <span class="token class-name">Callable</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">V</span><span class="token punctuation">&gt;</span></span> c <span class="token operator">=</span> callable<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>c <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> state <span class="token operator">==</span> <span class="token constant">NEW</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token class-name">V</span> result<span class="token punctuation">;</span>
   <span class="token keyword">boolean</span> ran<span class="token punctuation">;</span>
   <span class="token keyword">try</span> <span class="token punctuation">{</span>
    result <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 真正执行任务</span>
    ran <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><span class="token comment">// 执行成功，设置执行成功标志</span>
   <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    result <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    ran <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span><span class="token comment">// 有异常，执行失败</span>
    <span class="token function">setException</span><span class="token punctuation">(</span>ex<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 设置异常</span>
   <span class="token punctuation">}</span>
   <span class="token comment">// 如果执行成功，则设置返回结果</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>ran<span class="token punctuation">)</span>
    <span class="token function">set</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
 <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
  runner <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span><span class="token comment">// 无论是否执行成功，把runner设置为null</span>
  <span class="token keyword">int</span> s <span class="token operator">=</span> state<span class="token punctuation">;</span>
  <span class="token comment">// 处理中断</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>s <span class="token operator">&gt;=</span> <span class="token constant">INTERRUPTING</span><span class="token punctuation">)</span>
   <span class="token function">handlePossibleCancellationInterrupt</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * 设置执行结果
 */</span>
<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">V</span> v<span class="token punctuation">)</span> <span class="token punctuation">{</span>
 <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token constant">UNSAFE</span><span class="token punctuation">.</span><span class="token function">compareAndSwapInt</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> stateOffset<span class="token punctuation">,</span> <span class="token constant">NEW</span><span class="token punctuation">,</span> <span class="token constant">COMPLETING</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">// 执行完成，设置COMPLETING状态</span>
  outcome <span class="token operator">=</span> v<span class="token punctuation">;</span><span class="token comment">// 设置执行结果</span>
  <span class="token constant">UNSAFE</span><span class="token punctuation">.</span><span class="token function">putOrderedInt</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> stateOffset<span class="token punctuation">,</span> <span class="token constant">NORMAL</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 设置完结果，设置NORMAL状态</span>
  <span class="token function">finishCompletion</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 逐个唤醒waiters中的线程去获取执行结果</span>
 <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="_5-获取任务返回值get-方法"><a href="#_5-获取任务返回值get-方法" class="header-anchor">#</a> 5. 获取任务返回值get()方法</h2> <ol><li>任务状态为NORMAL，直接返回执行结果；</li> <li>任务状态为COMPLETING，线程yield()让出CPU，因为COMPLETING到NORMAL只需要很短的时间，get线程让出CPU的短暂时间，任务状态就是从COMPLETING变成了NORMAL；</li> <li>任务状态为NEW，将get线程阻塞，如果设置了超时，阻塞至超时时间；如果没有设置超时，会一直阻塞直到任务完成后唤醒。</li></ol> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token class-name">V</span> <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">ExecutionException</span> <span class="token punctuation">{</span>
 <span class="token keyword">int</span> s <span class="token operator">=</span> state<span class="token punctuation">;</span>
 <span class="token comment">// 如果状态处于NEW或者COMPLETING状态，表示任务还没有执行完成，awaitDone()等待</span>
 <span class="token keyword">if</span> <span class="token punctuation">(</span>s <span class="token operator">&lt;=</span> <span class="token constant">COMPLETING</span><span class="token punctuation">)</span>
  s <span class="token operator">=</span> <span class="token function">awaitDone</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token number">0L</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 下文详解</span>
 <span class="token comment">// 返回结果，下文详解</span>
 <span class="token keyword">return</span> <span class="token function">report</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * 返回执行结果
 */</span>
<span class="token keyword">private</span> <span class="token class-name">V</span> <span class="token function">report</span><span class="token punctuation">(</span><span class="token keyword">int</span> s<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ExecutionException</span> <span class="token punctuation">{</span>
 <span class="token class-name">Object</span> x <span class="token operator">=</span> outcome<span class="token punctuation">;</span>
 <span class="token comment">// 任务正常结束时，返回outcome</span>
 <span class="token keyword">if</span> <span class="token punctuation">(</span>s <span class="token operator">==</span> <span class="token constant">NORMAL</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token class-name">V</span><span class="token punctuation">)</span>x<span class="token punctuation">;</span>
 <span class="token comment">// 任务被取消了，抛出CancellationException</span>
 <span class="token keyword">if</span> <span class="token punctuation">(</span>s <span class="token operator">&gt;=</span> <span class="token constant">CANCELLED</span><span class="token punctuation">)</span>
  <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">CancellationException</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token comment">// 这里只能第EXCEPTIONAL状态，表示在执行过程中出现了异常，抛出ExecutionException。</span>
 <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ExecutionException</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Throwable</span><span class="token punctuation">)</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/**
 * 处于NEW或者COMPLETING状态时，get线程等待
 */</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> <span class="token function">awaitDone</span><span class="token punctuation">(</span><span class="token keyword">boolean</span> timed<span class="token punctuation">,</span> <span class="token keyword">long</span> nanos<span class="token punctuation">)</span>
  <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
 <span class="token comment">// ......</span>
 <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token punctuation">;</span><span class="token punctuation">;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// ......</span>
  <span class="token comment">// 任务处于COMPLETING中，就让当前线程先暂时放弃CPU的执行权</span>
  <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>s <span class="token operator">==</span> <span class="token constant">COMPLETING</span><span class="token punctuation">)</span> <span class="token comment">// cannot time out yet</span>
   <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token keyword">yield</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// ......         </span>
  <span class="token comment">// 如果设置了超时，阻塞至超时时间</span>
  <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>timed<span class="token punctuation">)</span> <span class="token punctuation">{</span>
   nanos <span class="token operator">=</span> deadline <span class="token operator">-</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">nanoTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span>nanos <span class="token operator">&lt;=</span> <span class="token number">0L</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">removeWaiter</span><span class="token punctuation">(</span>q<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> state<span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
   <span class="token comment">// 等待一段时间</span>
   <span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">parkNanos</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> nanos<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">else</span>
   <span class="token comment">// 如果没有设置超时，会一直阻塞，直到被中断或者被唤醒</span>
   <span class="token class-name">LockSupport</span><span class="token punctuation">.</span><span class="token function">park</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="_6-取消任务-cancel"><a href="#_6-取消任务-cancel" class="header-anchor">#</a> 6. 取消任务 cancel()</h2> <p>将任务状态设置成INTERRUPTING/INTERRUPTED/CANCELLED状态就表示取消了线程，因为在这些状态下任务的run方法是不能执行的。</p> <div class="language-java extra-class"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">cancel</span><span class="token punctuation">(</span><span class="token keyword">boolean</span> mayInterruptIfRunning<span class="token punctuation">)</span> <span class="token punctuation">{</span>
 <span class="token comment">/*
  * 以下情况不能取消任务：
  * 1. 当前任务不是NEW状态，已经被执行了，不能取消
  * 2. 当前任务还没有执行，state == NEW，但是CAS设置状态失败，不能取消
  */</span>
 <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span>state <span class="token operator">==</span> <span class="token constant">NEW</span> <span class="token operator">&amp;&amp;</span>
    <span class="token constant">UNSAFE</span><span class="token punctuation">.</span><span class="token function">compareAndSwapInt</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> stateOffset<span class="token punctuation">,</span> <span class="token constant">NEW</span><span class="token punctuation">,</span>
     mayInterruptIfRunning <span class="token operator">?</span> <span class="token constant">INTERRUPTING</span> <span class="token operator">:</span> <span class="token constant">CANCELLED</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
 <span class="token keyword">try</span> <span class="token punctuation">{</span>    <span class="token comment">// in case call to interrupt throws exception</span>
  <span class="token comment">// 中断</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>mayInterruptIfRunning<span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token class-name">Thread</span> t <span class="token operator">=</span> runner<span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>t <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
     t<span class="token punctuation">.</span><span class="token function">interrupt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 中断线程</span>
   <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span> <span class="token comment">// final state</span>
    <span class="token comment">// 中断之后，设置INTERRUPTED状态</span>
    <span class="token constant">UNSAFE</span><span class="token punctuation">.</span><span class="token function">putOrderedInt</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> stateOffset<span class="token punctuation">,</span> <span class="token constant">INTERRUPTED</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
 <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
  <span class="token function">finishCompletion</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 唤醒waiters中的线程去获取执行结果</span>
 <span class="token punctuation">}</span>
 <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="custom-block tip"><p class="custom-block-title">来源</p> <p><a href="https://mp.weixin.qq.com/s?__biz=MzAxMjEwMzQ5MA==&amp;mid=2448893268&amp;idx=2&amp;sn=a1aeb955fbbba6af7c0914abd3eb4399&amp;chksm=8fb57f79b8c2f66f3bf500776965d4fc305e273e408d7fc33c51da813ecfa8f237e98ce77186&amp;scene=178&amp;cur_album_id=1348578428257353729#rd" target="_blank" rel="noopener noreferrer">java进阶架构师<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></div></div></div> <!----> <div class="page-edit"><!----> <div class="tags"><a href="/tags/?tag=%E5%B9%B6%E5%8F%91%E5%A4%9A%E7%BA%BF%E7%A8%8B" title="标签">#并发多线程</a></div> <!----></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/pages/6c4806/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">线程池</div></a> <!----></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/pages/6c4806/" class="prev">线程池</a></span> <!----></p></div></div></div> <!----></main></div> <div class="footer"><div class="icons"><a href="mailto:likanjia@126.com" title="发邮件" target="_blank" class="iconfont icon-youjian"></a><a href="https://github.com/" title="GitHub" target="_blank" class="iconfont icon-github"></a><a href="https://music.163.com/#/playlist?id=755597173" title="听音乐" target="_blank" class="iconfont icon-erji"></a></div> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2019-2023
    <span>likanjie | MIT License</span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <!----> <!----> <!----></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.c5f14b06.js" defer></script><script src="/assets/js/2.0bb8723e.js" defer></script><script src="/assets/js/11.3f64ae04.js" defer></script>
  </body>
</html>
